package com.gitee.yongzhuzl.commonutil.util.code;

import com.gitee.yongzhuzl.commonutil.util.empty.EmptyUtil;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Base64;

/**
 * description: 编码工具类，包括BASE64编码解码、Unicode编码解码（仅支持中文）、URLCode编码解码
 * @author 朱正磊
 * @date 2018年10月25日 下午1:37:35
 */
public class CodeUtil {

    /**
     * description: 一次性判断多个或单个对象至少有一个为空。
     * @param objects 可变数组
     * @return 只要有一个元素为空，则返回true。
     */
    public static Boolean atLeastOneIsBlank(Object... objects) {
        if (EmptyUtil.isEmpty(objects)) {
            return true;
        }
        boolean result = false;
        for (Object object : objects) {
            if (EmptyUtil.isEmpty(object)) {
                result = true;
                break;
            }
        }
        return result;
    }

    //****************************************【BASE64编码解码】***********************************************//

    /**
     * description: 将字符串str进行BASE64编码
     * @param str 要编码的字符串
     * @param bl true|false,true:去掉结尾补充的'=',false:不做处理
     * @return 返回经过BASE64编码的字符串
     */
    public static String getBase64(String str, boolean... bl) {
        if (EmptyUtil.isEmpty(str)) {
            return null;
        }
        String base64 = Base64.getEncoder().encodeToString(str.getBytes());
        // bl为false
        if (EmptyUtil.isNotEmpty(bl) && !bl[0]) {
            return base64;
        }
        // 去掉"="，比如7dkbExN6+mybfpdZ0WrDVg==去掉=就是7dkbExN6+mybfpdZ0WrDVg
        // 不传布尔类型参数默认和bl为true相同
        if (EmptyUtil.isEmpty(bl) || bl[0]) {
            // 使用replaceAll()也可以。必须要重新赋值，仅调用方法是不行的
            base64 = base64.replace("=", "");
        }
        return base64;
    }

    /**
     * description: 将BASE64编码的字符串str进行解码
     * @param str 经过BASE64编码的字符串
     * @return 返回经过BASE64解码的字符串
     */
    public static String getStrByBase64(String str) {
        if (EmptyUtil.isEmpty(str)) {
            return "";
        }
        try {
            byte[] bytes = Base64.getDecoder().decode(str);
            return new String(bytes);
        } catch (Exception e) {
            return "";
        }
    }

    //****************************************【BASE64编码解码】***********************************************//

    //***************************************【Unicode编码解码】***********************************************//

    /**
     * description: 字符串转换为Unicode编码（字符串转16进制数）
     * @param str 字符串
     * @return 返回经过Unicode编码的字符串
     */
    public static String strToUnicode(String str) {
        String[] strArray = new String[str.length()];
        StringBuilder s = new StringBuilder();
        for (int i = 0; i < strArray.length; i++) {
            int num = str.charAt(i) & 0xffff;
            strArray[i] = Integer.toHexString(num);
            s.append("\\u").append(strArray[i]);
        }
        return s.toString();
    }

    /**
     * description: Unicode编码转中文字符串
     * （该方法貌似看似用不着，因为直接打印Unicode编码就可以得到我们想要的中文字符串）
     * @param unicode 经过Unicode编码的字符串
     * @return 返回经过Unicode解码的字符串
     */
    public static String unicodeToStr(String unicode) {
        int n = unicode.length() / 6;
        StringBuilder sb = new StringBuilder(n);
        for (int i = 0, j = 2; i < n; i++, j += 6) {
            String code = unicode.substring(j, j + 4);
            char ch = (char) Integer.parseInt(code, 16);
            sb.append(ch);
        }
        return sb.toString();
    }

    //***************************************【Unicode编码解码】***********************************************//

    //***************************************【URLCode编码解码】***********************************************//

    /**
     * description: 字符串转URLCode（URLCode编码）
     * @param str 字符串
     * @return 返回经过urlCode编码的字符串
     */
    public static String strToUrlCode(String str) {
        try {
            // 转码
            return URLEncoder.encode(str, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * description: URLCode转字符串（URLCode解码）
     * @param urlCode 经过urlCode编码的字符串
     * @return 返回经过URLCode解码的字符串
     */
    public static String urlCodeToStr(String urlCode) {
        try {
            // 解码
            return URLDecoder.decode(urlCode, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }

    //***************************************【URLCode编码解码】***********************************************//

    public static void main(String[] args) {

        String str = "123 甲乙  @ hehe...";

        // 1、BASE64编码解码
        String base64 = getBase64(str);
        // BASE64编码结果：MTIzIOeUsuS5mSAgQCBoZWhlLi4u
        System.out.println(base64);
        String strByBase64 = getStrByBase64(base64);
        // BASE64解码结果：123 甲乙  @ hehe...
        System.out.println(strByBase64);

        // 2、Unicode编码解码（有缺陷）
        String strToUnicode = strToUnicode("这种编码解码方式仅仅只支持中文字符串，阿拉伯数字和英文字母不支持！");
        // Unicode编码结果：这种编码解码方式仅仅只支持中文字符串，阿拉伯数字和英文字母不支持！
        System.out.println(strToUnicode);
        String unicodeToStr = unicodeToStr(strToUnicode);
        // Unicode解码结果：这种编码解码方式仅仅只支持中文字符串，阿拉伯数字和英文字母不支持！
        System.out.println(unicodeToStr);

        // 3、URLCode编码解码
        String strToUrlCode = strToUrlCode(str);
        // URLCode编码结果：123+%E7%94%B2%E4%B9%99++%40+hehe...
        System.out.println(strToUrlCode);
        String urlCodeToStr = urlCodeToStr(strToUrlCode);
        // URLCode解码结果：123 甲乙  @ hehe...
        System.out.println(urlCodeToStr);
    }

}
